#include <mutex>

#include "common/more/sha.h"

#include "user.h"

namespace Elements
{

User::User(const User& other)
    : Element(other)
    , m_login(other.m_login)
    , m_firstName(other.m_firstName)
    , m_middleName(other.m_middleName)
    , m_lastName(other.m_lastName)
    , m_email(other.m_email)
    , m_passwordHash(other.m_passwordHash)
    , m_needChangePassword(other.m_needChangePassword)
    , m_isBlocked(other.m_isBlocked)
    , m_uiLang(other.m_uiLang)
    , m_isOnline(other.m_isOnline)
{
}

bool User::isSame(Element* const other) const
{
    const auto otherElement = dynamic_cast<User const*>(other);
    if (nullptr == otherElement)
        return false;

    return bool(
        m_id == otherElement->m_id
        && m_login == otherElement->m_login
        && m_firstName == otherElement->m_firstName
        && m_middleName == otherElement->m_middleName
        && m_lastName == otherElement->m_lastName
        && m_email == otherElement->m_email
        && m_passwordHash == otherElement->m_passwordHash
        && m_needChangePassword == otherElement->m_needChangePassword
        && m_isBlocked == otherElement->m_isBlocked
        && m_uiLang == otherElement->m_uiLang
        && m_isOnline == otherElement->m_isOnline
    );
}

Common::Json User::toJson() const
{
    std::shared_lock locker(m_lock);
    Common::Json result;
    result["id"] = m_id;
    result["elementType"] = unsigned(elementType());
    result["login"] = m_login;
    result["firstName"] = m_firstName;
    result["middleName"] = m_middleName;
    result["lastName"] = m_lastName;
    result["email"] = m_email;
    result["passwordHash"] = m_passwordHash;
    result["needChangePassword"] = m_needChangePassword;
    result["isBlocked"] = m_isBlocked;
    result["uiLang"] = m_uiLang;
    result["isOnline"] = m_isOnline;
    return result;
}

void User::fromJson(const Common::Json& json)
{
    std::shared_lock locker(m_lock);
    m_id = json["id"].get<unsigned>();
    m_login = json["login"].get<std::string>();
    m_firstName = json["firstName"].get<std::string>();
    m_middleName = json["middleName"].get<std::string>();
    m_lastName = json["lastName"].get<std::string>();
    m_email = json["email"].get<std::string>();
    m_passwordHash = json["passwordHash"].get<std::string>();
    m_needChangePassword = json["needChangePassword"].get<bool>();
    m_isBlocked = json["isBlocked"].get<bool>();
    m_uiLang = json["uiLang"].get<std::string>();
    m_isOnline = json["isOnline"].get<bool>();
}

Element* User::clone() const
{
    return new User(*this);
}

ElementType User::elementType() const
{
    return ElementType::User;
}

std::string User::login() const
{
    std::shared_lock locker(m_lock);
    return m_login;
}

void User::setLogin(const std::string& value)
{
    std::unique_lock locker(m_lock);
    m_login = value;
}

std::string User::firstName() const
{
    std::shared_lock locker(m_lock);
    return m_firstName;
}

void User::setFirstName(const std::string& value)
{
    std::unique_lock locker(m_lock);
    m_firstName = value;
}

std::string User::middleName() const
{
    std::shared_lock locker(m_lock);
    return m_middleName;
}

void User::setMiddleName(const std::string& value)
{
    std::unique_lock locker(m_lock);
    m_middleName = value;
}

std::string User::lastName() const
{
    std::shared_lock locker(m_lock);
    return m_lastName;
}

void User::setLastName(const std::string& value)
{
    std::unique_lock locker(m_lock);
    m_lastName = value;
}

std::string User::email() const
{
    std::shared_lock locker(m_lock);
    return m_email;
}

void User::setEmail(const std::string& value)
{
    std::unique_lock locker(m_lock);
    m_email = value;
}

std::string User::passwordHash() const
{
    std::shared_lock locker(m_lock);
    return m_passwordHash;
}

void User::setPasswordHash(const std::string& value)
{
    std::unique_lock locker(m_lock);
    m_passwordHash = value;
}

bool User::needChangePassword() const
{
    std::shared_lock locker(m_lock);
    return m_needChangePassword;
}

void User::setNeedChangePassword(const bool value)
{
    std::unique_lock locker(m_lock);
    m_needChangePassword = value;
}

bool User::isBlocked() const
{
    std::shared_lock locker(m_lock);
    return m_isBlocked;
}

void User::setIsBlocked(const bool value)
{
    std::unique_lock locker(m_lock);
    m_isBlocked = value;
}

std::string User::uiLang() const
{
    std::shared_lock locker(m_lock);
    return m_uiLang;
}

void User::setUiLang(const std::string& value)
{
    std::unique_lock locker(m_lock);
    m_uiLang = value;
}

bool User::isOnline() const
{
    std::shared_lock locker(m_lock);
    return m_isOnline;
}

void User::setIsOnline(const bool value)
{
    std::unique_lock locker(m_lock);
    m_isOnline = value;
}

bool User::setPassword(const std::string& password)
{
    if (password.empty())
        return false;
    const auto passwordHashValue = Crypto::sha256(password);
    setPasswordHash(passwordHashValue);
    return true;
}

bool User::checkPassword(const std::string& password) const
{
    const auto passwordHashValue = Crypto::sha256(password);
    return bool(passwordHash() == passwordHashValue);
}

std::string User::fullName() const
{
    std::unique_lock locker(m_lock);
    std::string result = m_lastName;
    if (!m_firstName.empty())
        result += " " + m_firstName;
    if (!m_middleName.empty())
        result += " " + m_middleName;
    return result;
}

} // namespace Elements
